package cz.pproproj.aaservice.aasbllmodule;

import cz.pproproj.aaservice.aasbllmodule.authentication.AuthenticationUser;
import cz.pproproj.aaservice.aasbllmodule.authentication.AuthenticationDataAccess;
import cz.pproproj.aaservice.aasbllmodule.authorization.AuthorizationModuleAccess;
import cz.pproproj.aaservice.guimodule.BLLModuleAccess;
import cz.pproproj.aaservice.guimodule.model.AuthenticationException;
import cz.pproproj.aaservice.guimodule.model.AuthorizationRole;
import cz.pproproj.aaservice.guimodule.model.AuthorizationUser;
import cz.pproproj.aaservice.guimodule.model.Credentials;
import cz.pproproj.aaservice.guimodule.model.User;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author David
 * @since 18. 1. 2015
 */
@Component
public class BLLModuleAccessImpl implements BLLModuleAccess {

    private static final BllModuleContext _bllModuleContext = BllModuleContext.getInstance();

    private final AuthorizationModuleAccess _authorizationModuleAccess = _bllModuleContext.getAuthorizationDataAccess();


    @Override
    public User authenticate(Credentials credentials, String dataSource) throws AuthenticationException {
        AuthenticationDataAccess authenticationDataAccess = getAuthenticationDataAccess(dataSource);

        boolean authenticationSuccessful = authenticate(credentials, authenticationDataAccess);

        if (authenticationSuccessful) {
            return new User(credentials.getUsername());
        } else {
            return null;
        }
    }

    @Override
    public List<Credentials> getAllUsers(String dataSource) throws AuthenticationException {
         AuthenticationDataAccess dataAccess = getAuthenticationDataAccess(dataSource);
         List<AuthenticationUser> allUsers = dataAccess.getAllUsers();
         return transformAuthenticationUsersToCredentials(allUsers);
    }

    @Override
    public List<AuthorizationRole> getRolesFromUser(AuthorizationUser user) {
        return _authorizationModuleAccess.getRolesFromUser(user);
    }

    @Override
    public List<AuthorizationRole> getAllRoles() {
        return _authorizationModuleAccess.getAllRoles();
    }

    @Override
    public boolean removeRole(AuthorizationRole role) {
        return _authorizationModuleAccess.removeRole(role);
    }

    @Override
    public boolean addRole(AuthorizationRole role) {
        return _authorizationModuleAccess.addRole(role);
    }

    @Override
    public boolean removeMapping(AuthorizationUser user, List<AuthorizationRole> roles) {
        return _authorizationModuleAccess.removeMapping(user, roles);
    }

    @Override
    public boolean addMapping(AuthorizationUser user, List<AuthorizationRole> roles) {
        return _authorizationModuleAccess.addMapping(user, roles);
    }

    @Override
    public Map<AuthorizationUser, List<AuthorizationRole>> getAllMappings() {
        return _authorizationModuleAccess.getAllMappings();
    }

    @Override
    public boolean authorize(AuthorizationUser user, AuthorizationRole role) {
        return _authorizationModuleAccess.authorize(user, role);
    }

    private List<Credentials> transformAuthenticationUsersToCredentials(List<AuthenticationUser> allUsers) {
        List<Credentials> credentials = new ArrayList<>();
        for (AuthenticationUser user : allUsers) {
            credentials.add(new Credentials(user.getUserName(), user.getPassword()));
        }
        return credentials;
    }

    private boolean authenticate(Credentials credentials, AuthenticationDataAccess authenticationDataAccess) throws AuthenticationException {
        AuthenticationUser enteredCredentials = new AuthenticationUser(credentials.getUsername(), credentials.getPassword());
        return authenticationDataAccess.authenticate(enteredCredentials);
    }

    private AuthenticationDataAccess getAuthenticationDataAccess(String dataSource) throws AuthenticationException {
        AuthenticationDataAccess authenticationDataAccess = _bllModuleContext.getAuthenticationDataAccess(dataSource);
        if (authenticationDataAccess == null) {
            throw new AuthenticationException("Entered dataSource: " + dataSource + " does not exist");
        }
        return authenticationDataAccess;
    }
}
